#pragma once

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <mutex>
#include <atomic>
#include <random>
#include <fstream>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>
#include <iomanip>
#include "Log.hpp"
#include <filesystem>
#include <boost/algorithm/string.hpp>   // 需要下载boost库

namespace util_ns
{
    using namespace LogModule_ns;

    //     #define LINE 0
    //     #define INFO 1
    //     #define ERROR 2
    //     #define FATAL 3
    // #define LOG(level, format, out, ...)                 \
    //     {                                                \
    //         if (level > LINE)                            \
    //         {                                            \
    //             struct time_t t = time(0);               \
    //             struct tm *local = localtime(&t);        \
    //             char buffer[32];                         \
    //             strftime(buffer, 31, "%m-%d %T", local); \
    //             fprintf(out, "[%s][%s:%d]" format "\n", buffer, __FILE__, __LINE__, ##__VA_ARGS__); \
    //         }   \   
//     }
    // #define ILOG(format, out, ...) LOG(INFO, out, ##__VA_ARGS__);

    const std::string temp_path = "./temp/";

    class PathUtil
    {
    public:
        static std::string AddSuffix(const std::string &file_name, const std::string &suffix)
        {
            std::string path_name = temp_path;
            path_name += file_name;
            path_name += suffix;
            return path_name;
        }
        // 编译时需要有的临时文件
        // 构建源文件路径+后缀的完整文件名
        static std::string Src(const std::string &file_name)
        {
            return AddSuffix(file_name, ".cpp");
        }
        static std::string Exe(const std::string &file_name)
        {
            return AddSuffix(file_name, ".exe");
        }
        static std::string CompilerError(const std::string &file_name)
        {
            return AddSuffix(file_name, ".compile_error");
        }

        // 运行时需要的临时文件
        static std::string Stdin(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdin");
        }
        static std::string Stdout(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdout");
        }
        // 构建该程序对应的标准错误完整的路径+后缀名
        static std::string Stderr(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stderr");
        }
    };
    class FileUtil
    {
    public:
        static bool isExists(const std::string &file)
        {
            return std::filesystem::exists(file);
        }
        static bool readFile(const std::string &file, std::string &str, bool keep = true)
        {
            // DLOG(DEBUG) << "开始读取文件"  << file;

            std::ifstream in(file);
            if (!in.is_open())
            {
                DLOG(ERROR) << "打开文件失败！";
                return false;
            }
            std::string line;
            while (std::getline(in, line))
            {
                str += line;
                str += (keep ? "\n" : "");
            }
            return true;
        }
        static bool writeFile(const std::string &file_name, const std::string &str)
        {
            // DLOG(DEBUG) << "开始向文件" << file_name << "写入代码";
            std::ofstream file(file_name);
            if (!file.is_open())
            {
                return false;
            }
            file << str;
            file.close();
            return true;
        }
    };

    // 也可以用C++11的编译器自动检查写
    // 双指针写一个单例模式
    class Random
    {
    public:
        // 格式：6位十六进制随机数_2位十六进制atomic,输入总长度
        std::string GetRandomNum(int num = 8)
        {
            std::stringstream ss;
            int n = (num - 2) / 2;
            for (int i = 0; i < n; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << GetRandom();
            }
            // 添加分隔符
            ss << "_";
            // 我们希望atomic占有两个16进制位，那么，就要8bit，一个int可不是8bit,进行位运算
            size_t id = _id.fetch_add(1); // 返回的是添加之前的值
            ss << std::setw(2) << std::setfill('0') << std::hex << (id & 0xFF);
            // 重置：当id达到256时重置（因为0-255是有效范围，256开始超出两位十六进制）
            if (id >= 255)
            {
                _id.store(0);
            }
            return ss.str();
        }
        // 希望以随机数获得两位十六进制数字，两位十六进制数字一共8位，最大为255（0xFF）
        int GetRandom(int min = 0, int max = 255)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            std::uniform_int_distribution distribution(min, max);
            return distribution(_generator);
        }
        void SetSeed(int seed)
        {
            std::lock_guard<std::mutex> lock(_mtx);
            _generator.seed(seed);
        }

    private:
        friend class RandomGuard;
        Random()
            : _generator(_device()), _id(0)
        {
        }
        Random(const Random &rand) = delete;
        Random &operator=(const Random &rand) = delete;
        ~Random() = default;

    private:
        std::mutex _mtx;
        std::random_device _device;
        std::mt19937 _generator;
        std::atomic<size_t> _id;
    };

    class RandomGuard
    {
    public:
        static Random *GetInstance()
        {
            if (_ptr == nullptr)
            {
                std::lock_guard<std::mutex> lock(_smtx);
                // 双重检查
                if (_ptr == nullptr)
                {
                    _ptr = new Random();
                }
            }
            return _ptr;
        }
        static void Destory()
        {
            if (_ptr != nullptr)
            {
                delete _ptr;
                _ptr = nullptr;
            }
        }

    private:
        static std::mutex _smtx;
        static Random *_ptr;
    };
    std::mutex RandomGuard::_smtx;
    Random *RandomGuard::_ptr = nullptr;

    class JSON
    {
    public:
        static bool unserializer(const std::string &body, Json::Value &val)
        {
            Json::CharReaderBuilder _crb;
            std::unique_ptr<Json::CharReader> cr(_crb.newCharReader());
            std::string errs;
            bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);
            if (ret == false)
            {
                DLOG(WARNING) << "序列化失败！" << errs;
            }
            return ret;
        }
        static bool serializer(std::string &body, const Json::Value &val)
        {
            Json::StreamWriterBuilder _swb;
            std::unique_ptr<Json::StreamWriter> sw(_swb.newStreamWriter());
            std::stringstream ss;
            int ret = sw->write(val, &ss);
            if (ret != 0)
            {
                DLOG(WARNING) << "序列化失败！";
            }
            body = ss.str();
            return ret;
        }
    };

    class StringUtil
    {
    public:
        /*************************************
         * str: 输入型，目标要切分的字符串
         * target: 输出型，保存切分完毕的结果
         * sep: 指定的分割符
         * **********************************/
        static void SplitString(const std::string &str, std::vector<std::string>& target, const std::string &sep)
        {
            // boost split,token_compress_on表示开启压缩，"    "不会解析
            boost::split(target, str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
        }
    };
}
